/*
 * Copyright (C) 2020 Spreadtrum Communications Inc.
 *
 */
#include "../../spi/sprd_spi.h"
#include "sprd_panel.h"

static uint32_t lattice_fpga_id;
extern bool dual_lcd_display;

 struct spi_init_param spi_init_parm[] =
 {
	{
		sck_default,
		tx_neg_edge,
		rx_neg_edge,
		tx_rx_msb,
		rx_tx_mode,
		master_mode,
		0x0,
		24000000
	},
 };

static char cmd_init[] = {0xff, 0xa4, 0xc6, 0xf4, 0x8a};
static char cmd_checkid[] = {0xe0, 0x00, 0x00, 0x00};
static char cmd_en_prog[] = {0xc6, 0x00, 0x00, 0x00};
static char cmd_exit_prog1[] = {0x26, 0x00, 0x00, 0x00};
static char cmd_exit_prog2[] = {0xff, 0xff, 0xff, 0xff};
static char cmd_erase_device[] = {0x0e, 0x00, 0x00, 0x00};
static char cmd_init_addr[] = {0x46, 0x00, 0x00, 0x00};
static char cmd_transfer_file[] = {0x7a, 0x00, 0x00, 0x00};
static char cmd_read_status[] = {0x3c, 0x00, 0x00, 0x00};
static char cmd_test[] = {0xaa, 0xaa, 0xaa, 0xaa};

const char *fpga_get_name(void)
{
	const char *name;

#ifdef CONFIG_FPGA_SINGLE_DISPLAY
	return NULL;
#else
	if ((lattice_fpga_id == 0x012c) && dual_lcd_display) {
		name = "lattice_fpga";
		return name;
	} else {
		return NULL;
	}
#endif
}

static void fpga_power(void)
{
#ifdef CONFIG_FPGA_1V2EN
	sprd_gpio_request(NULL, CONFIG_FPGA_1V2EN);
	sprd_gpio_direction_output(NULL, CONFIG_FPGA_1V2EN, 1);
#endif

#ifdef CONFIG_FPGA_3V3EN
	sprd_gpio_request(NULL, CONFIG_FPGA_3V3EN);
	sprd_gpio_direction_output(NULL, CONFIG_FPGA_3V3EN, 1);
#endif

#ifdef CONFIG_FPGA_GPOEXT1_2V5EN
	aw9523_gpio_request(AW9523_ADDR59_GPIO_BASE + CONFIG_FPGA_GPOEXT1_2V5EN);
	aw9523_gpio_direction_output(AW9523_ADDR59_GPIO_BASE + CONFIG_FPGA_GPOEXT1_2V5EN, 1);
#endif

#ifdef CONFIG_FPGA_GPOEXT1_1V2EN
	aw9523_gpio_request(AW9523_ADDR59_GPIO_BASE + CONFIG_FPGA_GPOEXT1_1V2EN);
	aw9523_gpio_direction_output(AW9523_ADDR59_GPIO_BASE + CONFIG_FPGA_GPOEXT1_1V2EN, 1);
#endif
}

void lcd_load_bitfile(char *bitfile, unsigned int num)
{
	unsigned int id[4] = {0};
	unsigned int status[4] = {0};
	unsigned int len = 0;

	fpga_power();

	sprd_gpio_request(NULL, CONFIG_FPGA_GPIO_CRSTN);
	sprd_gpio_direction_output(NULL, CONFIG_FPGA_GPIO_CRSTN, 1);
	sprd_gpio_request(NULL, CONFIG_FPGA_GPIO_RSTN);//lreset
	sprd_gpio_direction_output(NULL, CONFIG_FPGA_GPIO_RSTN, 0);

	sprd_spi_enable(1);
	sprd_spi_clk_set(1, 3, 0);
	sprd_spi_init(spi_init_parm);
	sprd_spi_set_spi_mode(4);// 4wire 8bit sdi sdo
	sprd_spi_set_data_width(8);

	pr_info("lcd_load_bitfile start\n");
	//step 1: init
	sprd_gpio_set(NULL, CONFIG_FPGA_GPIO_CRSTN, 0);
	mdelay(100);
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_init, 5, 0);
	sprd_spi_set_cs(0, FALSE);
	mdelay(10);
	sprd_gpio_set(NULL, CONFIG_FPGA_GPIO_CRSTN, 1);
	mdelay(100);

	//step 2: check id
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_checkid, 4, 0);
	len = sprd_spi_read_data(id, 4, 0);
	sprd_spi_set_cs(0, FALSE);
	pr_info("lcd_load_bitfile id=%x,%x,%x,%x, read num = %d\n", id[0], id[1],id[2],id[3], len);
	if(id[0] == 0x01 && id[1] == 0x2c && id[2] == 0 && id[3] == 0x43)
	{
		lattice_fpga_id = 0x012c;
	}

	//step3: enable program mode
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_en_prog, 4, 0);
	sprd_spi_set_cs(0, FALSE);
	mdelay(1);

	//step 4: erase device
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_erase_device, 4, 0);
	sprd_spi_set_cs(0, FALSE);
	mdelay(200);

	//step 5: transfer bitfile
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_init_addr, 4, 0);
	sprd_spi_set_cs(0, FALSE);
	mdelay(10);
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_transfer_file, 4, 0);
	len = sprd_spi_write_data_bytes(bitfile, num, 0);
	pr_debug("bitfile transfer len=%d\n", len);
	sprd_spi_set_cs(0, FALSE);
	mdelay(10);

	//step 6: read status
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_read_status, 4, 0);
	len = sprd_spi_read_data(status, 4, 0);
	pr_debug("lcd_load_bitfile status=%x,%x,%x,%x, read num = %d\n", status[0], status[1],status[2],status[3], len);
	sprd_spi_set_cs(0, FALSE);

	//step 7: exit program mode
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_exit_prog1, 4, 0);
	sprd_spi_set_cs(0, FALSE);
	mdelay(200);
	sprd_spi_set_cs(0, TRUE);
	sprd_spi_write_data_bytes(cmd_exit_prog2, 4, 0);
	sprd_spi_set_cs(0, FALSE);

	sprd_spi_disable(1);
	pr_info("lcd_load_bitfile end\n");
}
